/*
 * @Author: your name
 * @Date: 2021-05-03 21:47:22
 * @LastEditTime: 2021-05-04 09:02:24
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \gcxz\Middlewares\Mydrives\uart_dma.c
 */
#include "uart_dma.h"

/**
 * @description: 暂时只支持uart2和uart4。只测试了uart2单独DMA，还未测试uart2和uart4同时DMA发送
 * 		必须在enable_irq之前调用，否则会出现一直进入tx中断
 * @param uart: 如 UART2
 * @return {*}
 */
void initUart_DMA(UART_Type* uart){
	static uint8 data[2] = {1,1};
	static int16 count = 0;
	uint8 dma_sources = 0, dma_channel = 0;
	uint32 dma_channel_mask = 0;

	if (uart == UART2){
		dma_sources = DMA_UART2_Tx;
		dma_channel = 14;	// DMA通道可以任意给，不要重复就可以
		dma_channel_mask = DMA_ERQ_ERQ14_MASK;
	} else if (uart == UART4){
		dma_sources = DMA_UART4_Rx_Tx;
		dma_channel = 15;
		dma_channel_mask = DMA_ERQ_ERQ15_MASK;
	} else{
		while(1){
			// 暂时只支持uart2和uart4
		}
	}

	uart->C2 |= UART_C2_TIE_MASK;           			//发送器或DMA中断使能
	uart->C5 |= UART_C5_TDMAS_MASK;
	SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;      			//使能DMA多路复用器时钟
	SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;         			//使能DMA模块时钟
	//UART_TX DMA设置
	DMAMUX->CHCFG[dma_channel] &= ~DMAMUX_CHCFG_ENBL_MASK;
	DMAMUX->CHCFG[dma_channel] |= DMAMUX_CHCFG_SOURCE(dma_sources); 		//DMA通道
	DMA0->TCD[dma_channel].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(count);  //当前主循环次数，采集点数（有多少个数据要发）
	DMA0->TCD[dma_channel].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(count);  
	DMA0->TCD[dma_channel].SADDR = (uint32_t)data;    						//源地址
	DMA0->TCD[dma_channel].SOFF = 1; 										//每次传送源地址+1
	DMA0->TCD[dma_channel].NBYTES_MLNO = DMA_NBYTES_MLNO_NBYTES(1);         //每次副循环读取一字节
	DMA0->TCD[dma_channel].SLAST = 0;                                       //主循环结束后源地址加0  
	DMA0->TCD[dma_channel].DLAST_SGA = 0;                                   //主循环结束后目的地址加0
	DMA0->TCD[dma_channel].DADDR = (uint32_t)&(uart->D);                    //目的地址  
	DMA0->TCD[dma_channel].DOFF = 0;                                        //每次写目的地址加0
	DMA0->TCD[dma_channel].ATTR = (DMA_ATTR_SSIZE(0) | DMA_ATTR_DSIZE(0));  //源数据宽度8bit，目的数据宽度8bit
	DMA0->TCD[dma_channel].CSR = DMA_CSR_DREQ_MASK;                         //DMA通道主循环结束后停止硬件请求
	DMAMUX->CHCFG[dma_channel] |= DMAMUX_CHCFG_ENBL_MASK;                   //DMA通道使能
	DMA0->ERQ |= dma_channel_mask;              							//使能通道请求	
}

void sendUart_DMA(UART_Type* uart, uint8* data,int16 count)
{
	uint8 dma_sources = 0, dma_channel = 0;
	uint32 dma_channel_mask = 0;

	if (uart == UART2){
		dma_sources = DMA_UART2_Tx;
		dma_channel = 14;	// DMA通道可以任意给，不要重复就可以
		dma_channel_mask = DMA_ERQ_ERQ14_MASK;
	} else if (uart == UART4){
		dma_sources = DMA_UART4_Rx_Tx;
		dma_channel = 15;
		dma_channel_mask = DMA_ERQ_ERQ15_MASK;
	} else{
		while(1){
			// 暂时只支持uart2和uart4
		}
	}
	
	DMA0->CDNE |= DMA_CDNE_CDNE(dma_channel);			                    //清完成标志
	DMA0->CERQ |= DMA_CERQ_CERQ(dma_channel);              					//清通道请求
	DMAMUX->CHCFG[dma_channel] &= ~DMAMUX_CHCFG_ENBL_MASK;
	DMAMUX->CHCFG[dma_channel] |= DMAMUX_CHCFG_SOURCE(dma_sources);         //DMA通道
	DMA0->TCD[dma_channel].CITER_ELINKNO = DMA_CITER_ELINKNO_CITER(count);  //当前主循环次数，采集点数
	DMA0->TCD[dma_channel].BITER_ELINKNO = DMA_BITER_ELINKNO_BITER(count);  //起始主循环次数，采集点数
	DMA0->TCD[dma_channel].SADDR = (uint32_t)data;    						//源地址
	DMA0->TCD[dma_channel].SOFF = 1; 										//每次传送源地址+1
	DMA0->TCD[dma_channel].DADDR = (uint32_t)&(uart->D);	                //目的地址	
	DMAMUX->CHCFG[dma_channel] |= DMAMUX_CHCFG_ENBL_MASK;					//使能通道
	DMA0->ERQ |= dma_channel_mask;              							//使能通道请求
}
